package leetcode.code0591;

import java.util.Stack;

public class Solution {

	public boolean isValid(String code) {
		char[] cs = code.toCharArray();
		int len = cs.length;
		int p = 0;
		char c = 0;
		Stack<String> names = new Stack<>();
		while (p < len) {
			if ((c = cs[p]) == '<') {
				p++;
				if (p == len) {
					return false;
				}
				if ((c = cs[p]) == '!') {
					if (++p == len || (c = cs[p++]) != '[') {
						return false;
					}
					StringBuffer cdataName = new StringBuffer();
					while (p < len && (c = cs[p++]) != '[') {
						cdataName.append(c);
					}
					if (p == len || !cdataName.toString().equals("CDATA")) {
						return false;
					} else {
						while (p < len) {
							c = cs[p];
							if (c == ']') {
								if (p + 1 == len || p + 2 == len) {
									return false;
								}
								if (cs[p + 1] == ']' && cs[p + 2] == '>') {
									p += 3;
									break;
								}
							}
							p++;
						}
						if (p == len) {
							return false;
						}
					}
				} else if (c == '/') {
					if (++p == len) {
						return false;
					}
					StringBuffer tagName = new StringBuffer();
					int ret = this.getTagName(tagName, cs[p], p, len, cs);
					if (ret == -1) {
						return false;
					} else {
						if (names.isEmpty() || !names.pop().equals(tagName.toString())) {
							// 不是闭合的标签
							return false;
						}
						p = ret + 1;
					}
				} else {
					StringBuffer tagName = new StringBuffer();
					int start = p;
					int ret = this.getTagName(tagName, c, p, len, cs);
					if (ret == -1 || ret == len) {
						return false;
					} else {
						// WA "<A></A><B></B>" false
						if (start != 1 && names.isEmpty()) {
							return false;
						}
						names.add(tagName.toString());
						p = ret + 1;
					}
				}
			} else {
				// WA "123456" false
				if (names.isEmpty()) {
					return false;
				}
				p++;
			}
		}
		return names.isEmpty();
	}

	private int getTagName(StringBuffer tagName, char c, int p, int len, char[] cs) {
		do {
			// 合法的 TAG_NAME 仅含有大写字母
			if (c < 'A' || c > 'Z') {
				return -1;
			}
			tagName.append(c);
		} while (++p < len && (c = cs[p]) != '>');
		// 长度在范围 [1,9] 之间
		int size = tagName.length();
		if (size < 1 || size > 9) {
			return -1;
		}
		return p;
	}

}
